# This script need mgdb.c, user must add mgdb.c into project.
# Here is a structure, which is define in mgdb.c.
#typedef struct {
#	volatile uint32_t ready;
#	volatile uint32_t inPos;
#	volatile uint32_t inLen;
#	volatile uint32_t bufLen;
#	volatile const char *outStart;
#	volatile const char *outEnd;
#	volatile uint8_t *buf;
#	volatile uint8_t inBuf[MGDB_IN_BUF_SIZE];
#} MGdb_t;

###############################################################################
# address of mgdb.ready
set $mgdb_ready = (unsigned int *)0

# how to halt the cpu. 0:watch 1:hb 2:b
set $mgdb_conf_breakpoint = 0

# use in cmd mgdb_config
set $mgdb_conf_stop  = 1

# [1:0] --> use mgdb_in_large or not
set $mgdb_flag  = (unsigned int)0
set $mgdb_ascii = (unsigned char[2049])""

###############################################################################
define mgdb_config
	if $argc == 0
		echo run finish when stop:
		if $mgdb_conf_stop
			printf " on\n"
		else
			printf " off\n"
		end
		echo stop cpu mode:
		if $mgdb_conf_breakpoint == 1
			printf " watch\n"
		else
			printf " breakpoint\n"
		end
	else
		set $mgdb_conf_stop = $arg0
		if $argc == 2
			set $mgdb_conf_breakpoint = $arg1
		end
	end
end

document mgdb_config
Usage: mgdb_config [stop] [mode]
like:  mgdb_config
       mgdb_config 1
       mgdb_config 1 0

If no parm, printf current configure.
If one parm, set stop action, 0:stop immediately, 1:run finish cmd \
before stop(default).
If two parm, set stop mode, 0:stop by watch(default), 1:stop by hard \
breakpoint, 2:stop by soft breakpoint.
end

###############################################################################
define mgdb_cmd0
	echo define mgdb_cmd0 please\n
end

document mgdb_cmd0
Usage: This cmd will run when procedure calls mGdbCmd(MGDB_CMD0), so user can redefine it.
like: (gdb) define mgdb_cmd0
      (gdb)     echo do mgdb_cmd0\n
      (gdb) end

This script support mgdb_cmd0 - mgdb_cmd5, total 6 commands.
end

###############################################################################
define mgdb_cmd1
	echo define mgdb_cmd1 please\n
end

document mgdb_cmd1
Usage: This cmd will run when procedure calls mgdbCmd(MGDB_CMD1), so user can redefine it.
like: (gdb) define mgdb_cmd1
      (gdb)     echo do mgdb_cmd1\n
      (gdb) end

This script support mgdb_cmd0 - mgdb_cmd5, total 6 commands.
end

###############################################################################
define mgdb_on
	# When use striped lib, there may be only has symbol but no structure
	# infomation. user need input the value of MGDB_IN_BUF_SIZE.
	if $argc == 1
		set $mgdb_in_sizes = $arg0
		set $mgdb_ready = (unsigned int *)&(mgdb)
		if $mgdb_conf_breakpoint != 0
			set $mgdb_bkpt = (unsigned int *)&(mGdbBkpt)
		end
	else
		# When no symbol table, user need input these two info.
		if $argc == 2
				set $mgdb_in_sizes = $arg0
				set $mgdb_ready = (unsigned int *)$arg1
			if $mgdb_conf_breakpoint != 0
				set $mgdb_bkpt = (unsigned int *)$arg2
			end
		else
			# When exist the complete symbol in elf file.
			if $mgdb_ready == 0
				set $mgdb_in_sizes = sizeof(mgdb.inBuf)
				set $mgdb_ready = (unsigned int *)&(mgdb.ready)
				if $mgdb_conf_breakpoint != 0
					set $mgdb_bkpt = (unsigned int *)&(mGdbBkpt)
				end
			end
		end
	end

	printf "$mgdb_ready: 0x%08X  $mgdb_in_sizes: %d\n", $mgdb_ready, $mgdb_in_sizes
	set $mgdb_i        = (unsigned int)$mgdb_ready
	set $mgdb_i       += sizeof(unsigned int)
	set $mgdb_inPos    = (unsigned int *)$mgdb_i
	set $mgdb_i       += sizeof(unsigned int)
	set $mgdb_inLen    = (unsigned int *)$mgdb_i
	set $mgdb_i       += sizeof(unsigned int)
	set $mgdb_bufLen   = (unsigned int *)$mgdb_i
	set $mgdb_i       += sizeof(unsigned int)
	set $mgdb_outStart = (char**)$mgdb_i
	set $mgdb_i       += sizeof(char *)
	set $mgdb_outEnd   = (char**)$mgdb_i
	set $mgdb_i       += sizeof(char *)
	set $mgdb_buf      = (unsigned char**)($mgdb_i)
	set $mgdb_i       += sizeof(unsigned char *)
	set $mgdb_inBuf    = (unsigned char *)($mgdb_i)

	if $mgdb_conf_breakpoint == 0
		watch *$mgdb_ready
	else
		if $mgdb_conf_breakpoint == 1
			hb *$mgdb_bkpt
		else
			b *$mgdb_bkpt
		end
	end
	commands
		silent
		set $mgdb_i = *$mgdb_ready
		if $mgdb_i < 2
			# In git bash for window, window gdb can't recognized /dev/stdout file.
			#dump binary memory ~/.gdb_out *$mgdb_outStart *$mgdb_outEnd
			#shell cat ~/.gdb_out
			
			# In cmd for window, window gdb can't recognized /dev/stdout file.
			#dump binary memory .gdb_out *$mgdb_outStart *$mgdb_outEnd
			#shell type .gdb_out
			
			# In Linux.
			dump binary memory /dev/stdout *$mgdb_outStart *$mgdb_outEnd
			c
		else
		if $mgdb_i < 4
			mgdb_cmd0
			c
		else
		if $mgdb_i < 6
			mgdb_cmd1
			c
		else
		if $mgdb_i < 8
			mgdb_cmd2
			c
		else
		if $mgdb_i < 10
			mgdb_cmd3
			c
		else
		if $mgdb_i < 12
			mgdb_cmd4
			c
		else
		if $mgdb_i < 14
			mgdb_cmd5
			c
		else
		if $mgdb_i < 16
			dump binary memory ~/.gdb_run_cmd *$mgdb_outStart *$mgdb_outEnd
			source ~/.gdb_run_cmd
			c
		else
		if $mgdb_i < 18
			if $mgdb_conf_stop
				finish
			end
			echo Stop\n
		else
		if $mgdb_i < 20
			q
		else
		if $mgdb_i < 22
			echo Input data use mgdb_in "data"\n
		end
		end
		end
		end
		end
		end
		end
		end
		end
		end
		end
	end
end

document mgdb_on
Usage: mgdb_on [mgdb_in_size] [mgdb_ready_addr] [bkpt_addr]

like: mgdb_on
      mgdb_on 1024
      mgdb_on 1024 0x20001700 0x10007C10

If have done "file *.elf", use "mgdb_on", gdb will get addr and size from elf symbol.
If the elf file is missing information about MGdb_t structure, user should tell gdb the size.
If no symbol table, user should tell gdb the addr and size.
end

###############################################################################
define mgdb_malloc
	if($argc == 2)
		set *$mgdb_buf = $arg0
		set *$mgdb_bufLen = $arg1
	else
		set *$mgdb_buf = 0
	end
end

document mgdb_malloc
Uasge: mgdb_malloc [addr] [sizes]

like: mgdb_malloc
      mgdb_malloc 0x20040000 1024

This cmd will changed malloc() return value, which is define in mgdb.c.
If "addr" exist, malloc() always return "addr", except malloc sizes is bigger \
then "sizes", it will return NULL.
If "addr" not exist, malloc() always return $mgdb_inBuf, if malloc sizes is \
bigger, it also return NULL.
If do not run this cmd, it as same as case in "addr" not exist.
end

###############################################################################
define mgdb_in
	if $mgdb_ready == 0
		echo Do "mgdb_on" first\n
	else
		set $mgdb_sizes = sizeof($arg0)-1

		if $mgdb_sizes > $mgdb_in_sizes
			echo Input data is too long, input:
			printf " %d, max: %d\n", $mgdb_sizes, $mgdb_in_sizes
		else
			set *$mgdb_inPos = 0
			set *$mgdb_inLen = $mgdb_sizes
			set $mgdb_i = 0
			while $mgdb_i < $mgdb_sizes
				set $mgdb_inBuf[$mgdb_i] = $arg0[$mgdb_i]
				set $mgdb_i++
			end
			if $argc == 1
				c
			end
		end
	end
end

document mgdb_in
Usage: mgdb_in [data] [anything to stop]

like: mgdb_in "123456"
      mgdb_in "\x12\x34"
      mgdb_in "\x12\x34" 1

"data" is a string, \x will transferred ascii to hex,
"mgdb_in" do not write '\0' which is end of string.
You can use mgdb_in "aa""\0""bb" to write a string with '\0'.
If you input two params, cmd will stop after complete.
If you want use "1234" instead of "\x12\x34", See "mgdb_in2".
end

###############################################################################
define mgdb_in2
	if $mgdb_ready == 1
		echo Do "mgdb_on" first\n
	else
		set $mgdb_sizes = sizeof($arg0)-1
		if $mgdb_sizes > sizeof($mgdb_ascii)
			echo Input data is too long, input:
			printf " %d, max: %d\n", $mgdb_sizes, sizeof($mgdb_ascii)
		else
			set $mgdb_ascii = $arg0
			set $mgdb_i = 0
			set $mgdb_j = 0
			set $mgdb_m = 0
			set $mgdb_n = 0
			set $mgdb_e = 1
			while $mgdb_ascii[$mgdb_i] && $mgdb_e
				# 'f':0x66 'a':0x61 'F':0x46 'A':0x41 '9':0x39 '0':0x30 ' ':0x20
				if $mgdb_ascii[$mgdb_i] != 0x20
					if $mgdb_ascii[$mgdb_i] > 0x66
						set $mgdb_e = 0
					else
						if $mgdb_ascii[$mgdb_i] > 0x60
							set $mgdb_m = $mgdb_ascii[$mgdb_i]-0x57
						else
							if $mgdb_ascii[$mgdb_i] > 0x46
								set $mgdb_e = 0
							else
								if $mgdb_ascii[$mgdb_i] > 0x40
									set $mgdb_m = $mgdb_ascii[$mgdb_i]-0x37
								else
									if $mgdb_ascii[$mgdb_i] > 0x39
										set $mgdb_e = 0
									else
										if $mgdb_ascii[$mgdb_i] > 0x2F
											set $mgdb_m = $mgdb_ascii[$mgdb_i]-0x30
										else
											set $mgdb_e = 0
										end
									end
								end
							end
						end
					end
					if ($mgdb_n == 0)
						set $mgdb_ascii[$mgdb_j] = $mgdb_m << 4
						set $mgdb_n = 1
					else
						set $mgdb_ascii[$mgdb_j] |= $mgdb_m
						set $mgdb_n = 0
						set $mgdb_j++
					end
				end
				set $mgdb_i++
			end
			if $mgdb_e == 0
				set $mgdb_i--
				printf "%c at %d is not \"a-f A-F 0-9\"\n", $arg0[$mgdb_i], $mgdb_i
			else
				if $mgdb_n == 1
					echo Input data len not align 2\n
				else
					if $mgdb_j > $mgdb_in_sizes
						echo Input data is too long, input:
						printf " %d, max: %d\n", $mgdb_j, $mgdb_in_sizes
					else
						set *$mgdb_inPos = 0
						set *$mgdb_inLen = $mgdb_j
						set $mgdb_i = 0
						while $mgdb_i < $mgdb_j
							set $mgdb_inBuf[$mgdb_i] = $mgdb_ascii[$mgdb_i]
							set $mgdb_i++
						end
						if $argc == 1
							c
						end
					end
				end
			end
		end
	end
end

document mgdb_in2
Usage: mgdb_in2 [data] [anything to stop]

like: mgdb_in2 "1234AB"
      mgdb_in2 "1234AB" 1

"data" is a string with "a-f A-F 0-9", it will be transferred to hex before \
write to memory. "mgdb_in2" do not write '\0'.
If you input two params, cmd will stop after complete.
If you want input a raw string, See "mgdb_in".
end

###############################################################################

#See also "mgdb_in_large".
#end

#define mgdb_in_large
#    if $mgdb_ready == 0
#        echo Do "mgdb_on" first\n
#    else
#        if ($mgdb_flag & 0x3) == 1
#            set $mgdb_sizes = sizeof($arg0)
#
#            if $mgdb_sizes > $mgdb_sizes
#                printf "Input data is too long, input: %d, max: %d\n", $mgdb_sizes, $mgdb_sizes
#            else
#                set *$gdb_in_pos = 0
#                set *$gdb_in_len = $mgdb_sizes-1
#                # gdb will call malloc() to get a memory, and restore $arg0 data to the memory.
#                # In gdb_io.c, the malloc() return memory address is $mgdb_buf, so it will be
#                # faster to write data to memory. If system use other malloc(), this cmd cannot used.
#                set $mgdb_buf = (unsigned char*)$arg0
#                c
#            end
#        else
#            if ($mgdb_flag & 0x3) == 0
#                set $mgdb_i = malloc(1)
#                if $mgdb_i != $mgdb_buf
#                    call free($mgdb_i)
#                    set $mgdb_flag |= 2
#                else
#                    set $mgdb_flag |= 1
#                    mgdb_in_large $arg0
#                end
#            else
#                echo Service conditions not satisfied\n
#            end
#        end
#    end
#end
#
#document mgdb_in_large
#Usage: mgdb_in_large data
#
#like: mgdb_in_large "123456"
#      mgdb_in_large "\x12\x34"
#
#Note: This cmd only can used when the malloc() function is provided by gdb_io.c
#
#This cmd will be quicker when large data to write, if only a few of data, use "mgdb_in".
#This cmd will write '\0' which is end of string to memory, but the gdb_io.in_len is not include this '\0'.
#
#See also "mgdb_in"
#end
